#include "dynamicTexture.h"

//-------------------------------------------- Unbind ---------------------------------------------------------//
void DynamicTexture::Unbind()
{
	glBindTexture( GL_TEXTURE_2D, replacedTexture );
}
//-------------------------------------------- Bind -----------------------------------------------------------//
void DynamicTexture::Bind()
{
	glGetIntegerv( GL_TEXTURE_BINDING_2D, &replacedTexture );
	glBindTexture( GL_TEXTURE_2D, texture.GetId() );
}
//-------------------------------------------- GenerateMipmaps ------------------------------------------------//
void DynamicTexture::GenerateMipmaps()
{
	int currentTexture;
	glGetIntegerv( GL_TEXTURE_BINDING_2D, &currentTexture );

	glBindTexture( GL_TEXTURE_2D, texture.GetId() );
	glGenerateMipmapEXT( GL_TEXTURE_2D );
	glBindTexture( GL_TEXTURE_2D, currentTexture );
}
//-------------------------------------------- EndTextureRendering --------------------------------------------//
void DynamicTexture::EndTextureRendering()
{
	//odbindowujemy FBO
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );

	//wracamy do starych usstawien
	glViewport( viewportX, viewportY, viewportWidth, viewportHeight );
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();
	gluPerspective( 54.0f, float(viewportWidth)/viewportHeight, 0.01, 1000.0f );
	glMatrixMode( GL_MODELVIEW );
}
//-------------------------------------------- BeginTextureRendering ------------------------------------------//
void DynamicTexture::BeginTextureRendering()
{
	//zapamietujemy ustawinia viewport
	int tmp[4];
	glGetIntegerv( GL_VIEWPORT, tmp );
	viewportX = tmp[ 0 ];
	viewportY = tmp[ 1 ];
	viewportWidth = tmp[ 2 ];
	viewportHeight = tmp[ 3 ];

	//zmieniamy ustawienia viewport aby pasowaly do tesktury
	glViewport( 0, 0, texture.GetWidth(), texture.GetHeight() );
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();
	gluPerspective( 60.0f, float(texture.GetWidth())/texture.GetHeight(), 0.01, 1000.0f );
	glMatrixMode( GL_MODELVIEW );

	//bindujemy FBO
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, FBOid );
}
//-------------------------------------------- ~DynamicTexture ------------------------------------------------//
DynamicTexture::~DynamicTexture()
{
	//sprzatamy
	uint tId = texture.GetId();
	glDeleteTextures( 1, &tId );
	glDeleteFramebuffersEXT( 1, &FBOid );
	glDeleteRenderbuffersEXT( 1, &RBOid );
}
//-------------------------------------------- InitializeDynamicTexture ---------------------------------------//
bool DynamicTexture::InitializeDynamicTexture()
{
	//zapamietujemy ostation zbindowana teksture
	int currentTexture;
	glGetIntegerv( GL_TEXTURE_BINDING_2D, &currentTexture );

	//tworzymy obiekt tekstury
	glGenTextures( 1, &texture.id );
	glBindTexture( GL_TEXTURE_2D, texture.GetId() );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

	//najpierw pytamy ogl'a czy jest wystarczajaco zasobow na utworzenie takiej tekstury
	int format;
	glTexImage2D( GL_PROXY_TEXTURE_2D, 0, texture.GetInternalFormat(), texture.GetWidth(), texture.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
	glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format);

	//nie ma zasobow - konczymy
	if( format != texture.GetInternalFormat() )
	{
		uint tId = texture.GetId();
		glDeleteTextures( 1, &tId );

		lastError = "Not enough resources to create texture.\n";
		return false;
	}

	//sa zasoby - tworzymy teksture. Uwaga! Wazne aby tutajj wygenerwowac mipmapy dla utworzonej tekstury! Bez tego sie MOZE (ale nie musi) sie krzaczyc (wysyla GL_FRAMEBUFFER_UNSUPPORTED_EXT)
	glTexImage2D( GL_TEXTURE_2D, 0, texture.GetInternalFormat(), texture.GetWidth(), texture.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
	glGenerateMipmapEXT(GL_TEXTURE_2D);

	//powracamy do starej tesktury
	glBindTexture( GL_TEXTURE_2D, currentTexture );

	//tworzymy FBO
	glGenFramebuffersEXT( 1, &FBOid );
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, FBOid );

	//tworzymy render buffer object
	glGenRenderbuffersEXT( 1, &RBOid );
	glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, RBOid );
	glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, texture.GetWidth(), texture.GetHeight() );
	glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );

	//attachujemy texture image i renderbuffer image
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture.GetId(), 0 );
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, RBOid );

	//sprawdzamy czy wszystko ok
	if( !CheckFramebufferStatus() )
	{
		//sprzatamy
		uint tId = texture.GetId();
		glDeleteTextures( 1, &tId );
		glDeleteFramebuffersEXT( 1, &FBOid );
		glDeleteRenderbuffersEXT( 1, &RBOid );
		texture.id = 0;
		texture.width = -1;
		texture.height = -1;
		texture.colorType = -1;
		texture.texType = -1;
		texture.areMipmaps = 0;

		//nie udalo sie
		return false;
	}

	//odbindowujemy
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );

	//sukces
	return true;
}
//-------------------------------------------- CheckFramebufferStatus --------------------------------------//
bool DynamicTexture::CheckFramebufferStatus()
{
    // check FBO status
    GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    switch(status)
    {
    case GL_FRAMEBUFFER_COMPLETE_EXT:
        return true;

    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
        lastError = "[ERROR] Framebuffer incomplete: Attachment is NOT complete.\n";
        return false;

    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
        lastError = "[ERROR] Framebuffer incomplete: No image is attached to FBO.\n";
        return false;

    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
        lastError = "[ERROR] Framebuffer incomplete: Attached images have different dimensions.\n";
        return false;

    case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
        lastError = "[ERROR] Framebuffer incomplete: Color attached images have different internal formats.\n";
        return false;

    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
        lastError = "[ERROR] Framebuffer incomplete: Draw buffer.\n";
        return false;

    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
        lastError = "[ERROR] Framebuffer incomplete: Read buffer.\n";
        return false;

    case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
        lastError = "[ERROR] Unsupported by FBO implementation.\n";
        return false;

    default:
        lastError = "[ERROR] Unknow error.\n";
        return false;
    }
}
